

#include "MyPlayer.h"
#include "MyGame.h"
#include "MyEngine.h"
#include "MyEnemies.h"
#include "MyUniversal.h"
#include "MyDefinitions.h"
#include "MyShots.h"
#include "MyMessages.h"
#include "MyPlayerActionManager.h"

//INIT -- constr / destr
MyPlayer::MyPlayer(MyGame* _this) { 	
	parent = _this; 
	first = 1;
	load_imgs();
	kill_cap = 20;
};
MyPlayer::~MyPlayer(){ 
#ifdef _DEBUG
	printf("destroyed player\n");
#endif
}
void MyPlayer::reset()
{
	old_x_pos = old_y_pos = speed_x = speed_y = acc_x = acc_y = 0;
	enemiesKilled = exp = money = shotWaited = spellWaited  = 0;
	timeMoving = shotPause = moveType = movement_phase = movementDirection = 0;
	level = 1;
	set_max_life(STANDARD_PLAYER_LIFE);
	set_max_mana(STANDARD_PLAYER_MANA);
	set_weapon_angle(30.0);
	center();
	movementPause = 5;
	shotPause = STANDARD_SHOT_PAUSE;
}
void MyPlayer::center(){ pos_x = ((FIELD_W - PLAYER_W)/2); pos_y = (FIELD_Y + (FIELD_H - PLAYER_H)/2); }
void MyPlayer::load_imgs()
{
	#ifdef _WIN32
	playerSheet = load_image( "misc\\player.png" );
	#else
	playerSheet = load_image( "misc/player.png" );	
	#endif

	if (!playerSheet)
		{	
			printf("ERROR:Cannot load game images!\n ('player.png' missing?)");
			parent->parent->goto_gs(ES_QUIT);
		}	    
}
/********************ENCAPSULATION FUNCTIONS*****************start*/
int MyPlayer::get_level() {return level;}
void MyPlayer::level_up(){//not sure of the values; //TODO: some extra graphics, speciality choose, etc
	level++;
	set_max_life(get_max_life()+5);	 //inc life, refill 
	set_max_mana(get_max_mana()+15); //inc mana, refill
	parent->level_up_trigger();
}
//exp functions
void MyPlayer::set_exp_d(int _exp) {
	exp += _exp;
	if (exp > get_exp_needed(get_level())) level_up();
}
int MyPlayer::get_exp_line_size(){ return int((exp%1300)/1.625f); }
int MyPlayer::get_money(){return money;}
void MyPlayer::set_money_d(int _m){money += _m;}
int MyPlayer::get_exp_cur() {return exp;}
int MyPlayer::get_exp_needed(int _level){ return _level*1300; }
void MyPlayer::enemy_killed(){ enemiesKilled++; }
int MyPlayer::get_enemies_killed(){ return enemiesKilled; }
int MyPlayer::get_random_boost(){ 
	switch(oneToXRand(4))
	{
	case 1:
		set_exp_d(500);
		return 1;
	case 2: 
	 	set_max_life(max_life + 10);
		return 2;
	case 3:
		set_max_mana(max_mana + 15);
		return 3;
	case 4:
		if (oneToXRand(10) == 7)
		{
			set_money_d(1000);
			return 4;
		}
		else
		{
			return 5;
		}
	}
	return -1;
}
//position functions -- absolute get, relative get, absolute set and relative set
double MyPlayer::get_pos_x(){ return pos_x;}
double MyPlayer::get_pos_y(){ return pos_y;}
void MyPlayer::set_pos_dx(double _x){
	//add the diff in x; perform boundary check
	pos_x += _x;	
	if (pos_x < 0) pos_x = 0;
	if (pos_x > FIELD_W - PLAYER_W) pos_x = FIELD_W - PLAYER_W;
}
void MyPlayer::set_pos_dy(double _y){
	pos_y += _y;	
	if (pos_y > INFOBAR_Y - PLAYER_H) pos_y = INFOBAR_Y - PLAYER_H;
	if (pos_y < FIELD_Y - PLAYER_H +1 ) pos_y = FIELD_Y - PLAYER_H + 1;	
}
//acceleration functions
double MyPlayer::get_acc_x(){return acc_x;}
double MyPlayer::get_acc_y(){return acc_y;}
void MyPlayer::set_acc_x(double _x){acc_x = _x;}
void MyPlayer::set_acc_y(double _y){acc_y = _y;}
//speed functions
double MyPlayer::get_speed_x(){return speed_x;}
double MyPlayer::get_speed_y(){return speed_y;}
void MyPlayer::set_speed_dx(double _x){
	speed_x += _x;
	if (speed_x > MAX_PLAYER_SPEED) speed_x = MAX_PLAYER_SPEED;
	if (speed_x < -MAX_PLAYER_SPEED) speed_x = -MAX_PLAYER_SPEED;
}
void MyPlayer::set_speed_dy(double _y){
	speed_y += _y;
	if (speed_y > MAX_PLAYER_SPEED) speed_y = MAX_PLAYER_SPEED;
	if (speed_y < -MAX_PLAYER_SPEED) speed_y = -MAX_PLAYER_SPEED;
}
//life functions
int MyPlayer::get_cur_life(){return cur_life;}
int MyPlayer::get_max_life(){return max_life;}
void MyPlayer::set_cur_life(int _life){
	cur_life = _life; 	
	if (cur_life <= 0) player_died();
}
void MyPlayer::set_max_life(int _life){max_life = _life; cur_life = _life;}
//mana functions
int MyPlayer::get_cur_mana(){return cur_mana;}
int MyPlayer::get_max_mana(){return max_mana;}
void MyPlayer::set_cur_mana(int _mana){cur_mana = _mana;}
void MyPlayer::set_max_mana(int _mana){max_mana = _mana; cur_mana = _mana;}
//weapon angle functions
double MyPlayer::get_weapon_angle()
{//returns the angle in radians
 return weapon_angle;
}
void MyPlayer::set_weapon_angle(double _wa){weapon_angle = _wa;}
void MyPlayer::set_weapon_angle_d(double _wa){weapon_angle += _wa;}
//game logic functions
void MyPlayer::player_died(){  parent->process_player_death();  }
void MyPlayer::move_player(int _t)
{	
	old_x_pos = pos_x; 
    old_y_pos = pos_y;

	//change the speed accordingly to speedups and movement direction;	
	//slow the player down due to the friction etc
	//functions will handle too high speed	
	set_speed_dx(get_acc_x()*SPEEDUP_X);
	speed_x	*= FRICTION_X;
	set_speed_dy(get_acc_y()*SPEEDUP_Y);
	speed_y *= FRICTION_Y;	
	//calculate the new position, functions will handle the boundaries AND update rel pos
	set_pos_dx(speed_x);
	set_pos_dy(speed_y);
	
	//movement phase calculation; use timer's flag to indicate the current state
	switch(sgn(acc_x))
	{
	//standing
	case 0:	{
		if (movementDirection == 0)
			{
			//count standing time
			movement_phase = 0;
			}
		else
		{//change the state to standing
		movementDirection = 0;
		moveType = PM_MOVE_RIGHT;
		movement_phase = 0;
		}
		break;
		}		
	case 1:	{//moves right
			if (movementDirection == 1) 
			{
			timeMoving += _t;
			timeMoving %= TIME_INTERVAL;
			movement_phase = decide_phase();
			}
			else
			{
			//Set the animation to right
			movementDirection = 1;
			timeMoving = 0;
			moveType = PM_MOVE_RIGHT;
			movement_phase = 0;
			}
			break;
		}
	case -1:{
			if (movementDirection == 2) 
			{
			timeMoving += _t;
			timeMoving %= TIME_INTERVAL;
			movement_phase = decide_phase();
			}
			else
			{
			//Set the animation to left
			movementDirection = 2;
			timeMoving = 0;
			moveType = PM_MOVE_LEFT;        
			movement_phase = 0;
			}
			break;
			}    
	}

	if (enemiesKilled >= kill_cap)
	{
		kill_cap += (level*5) + 20;
		parent->actGameState = GS_LVLFINISHED;
	}
	
	//Loop the animation
	if (movement_phase == MF_FRAMES) { printf("EVER HERE? #1");	movement_phase = 0;	}
	if ((movement_phase < 1 ) && (movementDirection)) { movement_phase = MF_FRAMES-1; }
	shotWaited -= _t;
	spellWaited -= _t;
	//actual drawing
	draw_player();
}

void MyPlayer::player_shoot(int _t, int _type)
{
	//if spell
	if (parent->actProjectils->shotTypeArray[_type].mana_consume)
	{
		//have enough consume mana, so test if it were possible
		if (cur_mana >= parent->actProjectils->shotTypeArray[_type].mana_consume)
		{		
			//can shoot only if pause is over
			if (spellWaited <= 0)
			{
				//decide what side are we shooting at
				if (get_weapon_angle() < M_PI * 0.5)
					//right, //add new shot to actProjectils
					parent->actProjectils->add_projectile(
					get_pos_x() + PLAYER_W * 0.55,// + 1/sin(get_weapon_angle()),	
					get_pos_y() + PLAYER_H * 0.3,// + 5*cos(get_weapon_angle()),
					get_weapon_angle(),
					&(parent->actProjectils->shotTypeArray[_type]), OT_PLAYER, 
					parent->actPlayerActionManager->getActSpellDmg());
				else
					//left, //add new shot to actProjectils
					parent->actProjectils->add_projectile(
					get_pos_x() + PLAYER_W * 0.45,	
					get_pos_y() + PLAYER_H * 0.3,
					get_weapon_angle(),
					&(parent->actProjectils->shotTypeArray[_type]),OT_PLAYER,
					parent->actPlayerActionManager->getActSpellDmg());	

		
				spellWaited = shotPause; //spellPause?			
				cur_mana -= parent->actProjectils->shotTypeArray[_type].mana_consume;
			}
		}
	}
	else
	{
		//can shoot only if pause is over
		if (shotWaited <= 0)
		{
			//decide what side are we shooting at
			if (get_weapon_angle() < M_PI * 0.5)
				//right, //add new shot to actProjectils
				parent->actProjectils->add_projectile(
				get_pos_x() + PLAYER_W * 0.55,// + 1/sin(get_weapon_angle()),	
				get_pos_y() + PLAYER_H * 0.3,// + 5*cos(get_weapon_angle()),
				get_weapon_angle(),
				&(parent->actProjectils->shotTypeArray[_type]), OT_PLAYER, 
				parent->actPlayerActionManager->getActShotDmg());
			else
				//left, //add new shot to actProjectils
				parent->actProjectils->add_projectile(
				get_pos_x() + PLAYER_W * 0.45,	
				get_pos_y() + PLAYER_H * 0.3,
				get_weapon_angle(),
				&(parent->actProjectils->shotTypeArray[_type]),OT_PLAYER, 
				parent->actPlayerActionManager->getActShotDmg());	
	
			shotWaited = shotPause; 		
		}
	}
}
void MyPlayer::draw_player(){
	SDL_Rect *tmp1 = make_rect(movement_phase*PLAYER_W,moveType*PLAYER_H,PLAYER_W,PLAYER_H);
	SDL_Rect *tmp2 = make_rect(int(pos_x), int(pos_y), PLAYER_W,PLAYER_H);	
	SDL_BlitSurface	(playerSheet,tmp1,parent->parent->screen,tmp2);	
	delete(tmp1);
	delete(tmp2);
}
int MyPlayer::decide_phase()
{
	         if (timeMoving < 1 * TIME_INTERVAL / MF_MOVEFRAMES) return 7;
		else if (timeMoving < 2 * TIME_INTERVAL / MF_MOVEFRAMES) return 6;
		else if (timeMoving < 3 * TIME_INTERVAL / MF_MOVEFRAMES) return 5;
		else if (timeMoving < 4 * TIME_INTERVAL / MF_MOVEFRAMES) return 4;
		else if (timeMoving < 5 * TIME_INTERVAL / MF_MOVEFRAMES) return 3;
		else if (timeMoving < 6 * TIME_INTERVAL / MF_MOVEFRAMES) return 2;
		else return 1;
}
void MyPlayer::loose_life(int dmgTaken)	{ set_cur_life(this->get_cur_life() - dmgTaken); }
SDL_Rect* MyPlayer::get_hit_zone()
{
	//returns the zone of player to by compared with shot

	if (sgn(get_acc_x()) < 0)			//player moving left
	{		
		return make_rect(int(pos_x+20), int(pos_y+7), 20, 63); 	
	}
	else if (sgn(get_acc_x()) > 0)		//player moving right 
	{
		return make_rect(int(pos_x+25), int(pos_y+6), 20, 63); 
	}
	else								//player standing
		return make_rect(int(pos_x+29), int(pos_y+5), 20, 63); 
}
